import copy
from kubernetes import client, config
import re, os
from .kubePrometheus import KubeScheduling

class KubernetesManager:
    def __init__(self):
        try:
            # config.load_kube_config()
            config.load_kube_config('/etc/kubernetes/admin.conf')
        except Exception as e:
            print('KubernetesManager init error:', e)
            config.load_incluster_config()
        self.v1 = client.CoreV1Api()
        self.api_instance = client.AppsV1Api()
        # self.kubeScheduler = KubeScheduling()

    def create_deployment_and_service(self, namespace, container_name, teaching_source_dir,student_work_dir, ingress_dir):
        try:
            if not os.path.exists(student_work_dir):
                os.makedirs(student_work_dir)
            if not os.path.exists(teaching_source_dir):
                os.makedirs(teaching_source_dir)
            # best_node_name = self.kubeScheduler.get_best_node()
            # 定义权限（例如：777）
            permission = 0o777
            # 修改目录权限
            os.chmod(student_work_dir, permission)
            os.chmod(teaching_source_dir, permission)
            # 上面的代码只是把当前目录权限改成了777，需要把所有父目录的权限都改成777
            
            parent_dir = os.path.dirname(student_work_dir)
            while parent_dir != '/nfs':
                os.chmod(parent_dir, permission)
                parent_dir = os.path.dirname(parent_dir)
            
            task_name = teaching_source_dir.split("/")[2:]
            task_name = "-".join(task_name)
            task_name = task_name.lower()
            container_name = container_name.lower()
            task_type, task_id, user_id = container_name.split("-")
            namespace = namespace.lower()
            print('kubeManager.py task_name = ', task_name)
            print('kubeManager.py container_name = ', container_name)
            # # 创建 ConfigMap
            jupyter_config_content = [
                """c.ServerApp.tornado_settings ={ 
                'headers':
                    { 
                    'Content-Security-Policy': "frame-ancestors * 'self' "
                    }
                }\n
                """,
                # "c.ServerApp.notebook_dir = '/app'\n",
                "c.ServerApp.root_dir = '/app'\n",
                "c.ServerApp.allow_root =True\n",
                # "c.ServerApp.ip = '0.0.0.0'\n",
                "c.ServerApp.ip = '*'",
                "c.ServerApp.disable_check_xsrf = True  # 跨站请求伪造（Cross-Site Request Forgery, XSRF）保护的启用或禁用",
                "c.ServerApp.allow_remote_access = True",
                
            ]
            jupyter_config_content = '\n'.join(jupyter_config_content)

            config_map_manifest = {
                'apiVersion': 'v1',
                'kind': 'ConfigMap',
                'metadata': {
                    'name': f'{container_name}-notebook-config'
                },
                'data': {
                    'jupyter_notebook_config.py': jupyter_config_content
                }
            }
            try:
                self.v1.read_namespaced_config_map(name= f'{container_name}-notebook-config', namespace=namespace)
                print("ConfigMap 'notebook-config' 已经存在.")
            except client.exceptions.ApiException as e:
                print("ConfigMap not found. Creating...")
                if e.status == 404:
                    resp = self.v1.create_namespaced_config_map(body=config_map_manifest, namespace=namespace)
                    print("ConfigMap created. status='%s'" % resp)
                else:
                    raise e
            # 创建 Deployment
            deployment_manifest = {
                'apiVersion': 'apps/v1',
                'kind': 'Deployment',
                'metadata': {
                    'name': f'{container_name}',
                    'labels':{
                        'task_type': f'{task_type}',
                        'user_id': f'{user_id}',
                        'task_id': f'{task_id}',
                    }
                },
                'spec': {
                    'replicas': 1,
                    'selector': {
                        'matchLabels': {
                            'app': f'{container_name}'
                        }
                    },
                    'template': {
                        'metadata': {
                            'labels': {
                                'app': f'{container_name}',
                                'task_type': f'{task_type}',
                                'user_id': f'{user_id}',
                                'task_id': f'{task_id}',
                            }
                        },
                        'spec': {
                            # 'nodeName': best_node_name,
                            'containers': [
                                {
                                    'name': f'{container_name}-container',
                                    'image': '172.20.216.103:8998/big_data_image/python@sha256:2681361911c424cf50de50936fbbae92e985da10f609876965cdb741515c71af',
                                    # 'image':'172.20.216.103:8998/big_data_image/python@sha256:5346d4346a13c35413d9b72fbd48991281c2ff3c3feb92e5aebfc600f194bf3a',
                                    # 'command': ["/bin/bash", "-ce", "tail -f /dev/null"],
                                    'ports': [
                                        {
                                            'containerPort': 80
                                        }
                                    ],
                                    'volumeMounts': [
                                        {
                                            'name': f'{container_name}-notebook-volume',
                                            'mountPath': '/root/.jupyter'
                                        },
                                        {
                                            'name': f'{task_name}-tea-volume',
                                            'mountPath': '/app/resource',
                                            'readOnly': True
                                        },
                                        {
                                            # 这个容器的路径作为用户的提交路径，用户只能在这个文件夹下提交内容
                                            'name': f'{task_name}-stu-volume',
                                            'mountPath': '/app',
                                        }
                                    ],
                                    # 'securityContext': {  # 设置容器运行的用户为 root 用户
                                    #     'runAsUser': 0,
                                    #     'privileged': True  ,
                                    # }
                                }
                            ],
                            #  'imagePullSecrets': [
                            #     {
                            #         'name': 'harbor-secret'
                            #     }
                            # ],
                            'volumes': [
                                {
                                    'name': f'{container_name}-notebook-volume',
                                    'configMap': {
                                        'name': f'{container_name}-notebook-config'
                                    }
                                },
                                # 添加软链接挂载目录的配置
                                {
                                    'name': f'{task_name}-tea-volume',
                                    'hostPath': {
                                        'path': teaching_source_dir,
                                    }
                                },
                                # 添加软链接挂载目录的配置
                                {
                                    'name': f'{task_name}-stu-volume',
                                    'hostPath': {
                                        'path': student_work_dir,
                                    }
                                }
                            ]
                        }
                    }
                }
            }
            print('kubeManager.py student_work_dir = ', student_work_dir)
            print('kubeManager.py teaching_source_dir = ', teaching_source_dir)
            try:
                self.api_instance.read_namespaced_deployment(name=deployment_manifest['metadata']['name'], namespace=namespace)
                print(f"Deployment '{deployment_manifest['metadata']['name']}' 已经存在.")
            except client.exceptions.ApiException as e:
                print("Deployment not found. Creating...")
                if e.status == 404:
                    resp = self.api_instance.create_namespaced_deployment(body=deployment_manifest, namespace=namespace)
                    print("Deployment created. status='%s'" % resp)
                else:
                    raise e

            # 创建 Service
            service_manifest = {
                'apiVersion': 'v1',
                'kind': 'Service',
                'metadata': {
                    'name': f'{container_name}',
                    'labels':{
                        'task_type': f'{task_type}',
                        'user_id': f'{user_id}',
                        'task_id': f'{task_id}',
                    }
                },
                'spec': {
                    'selector': {
                        'app': f'{container_name}'
                    },
                    'ports': [
                        {
                            'protocol': 'TCP',
                            'port': 80,
                            'targetPort': 80
                        }
                    ],
                    'type': 'LoadBalancer' # 如果有这一行，那么会自动生产端口，30000-32767，可以通过端口访问容器。
                }
            }

            try:
                self.v1.read_namespaced_service(name=service_manifest['metadata']['name'], namespace=namespace)
                print(f"Service '{service_manifest['metadata']['name']}' 已经存在.")
            except client.exceptions.ApiException as e:
                print("Service not found. Creating...")
                if e.status == 404:
                    resp = self.v1.create_namespaced_service(body=service_manifest, namespace=namespace)
                    print("Service created. status='%s'" % resp)
                else:
                    raise e
                
                
            # self.update_ingress_with_new_pod(namespace, ingress_dir, container_name)

                
            return True
        except Exception as e:
            print('KubernetesManager create_deployment_and_service error:', e)
            return False
    
    
    def update_ingress_with_new_pod(self, namespace, ingress_dir, new_service_name):
        try:
            # 尝试读取现有的 Ingress
            v1 = client.NetworkingV1Api()
            ingress = v1.read_namespaced_ingress(name=ingress_dir, namespace=namespace)

            # 复制现有配置以便修改
            new_ingress = copy.deepcopy(ingress)

            # 创建新的路径配置
            new_path = {
                'path': f'/{ingress_dir}/{new_service_name}',
                'pathType': 'Prefix',
                'backend': {
                    'service': {
                        'name': new_service_name,
                        'port': {
                            'number': 80
                        }
                    }
                }
            }

            # 将新的路径配置添加到 Ingress 规则中
            new_ingress.spec.rules[0].http.paths.append(new_path)

            # 更新 Ingress
            resp = v1.replace_namespaced_ingress(name=ingress_dir, namespace=namespace, body=new_ingress)
            print("Ingress updated. status='%s'" % resp)
        except client.exceptions.ApiException as e:
            if e.status == 404:
                # 如果不存在，则创建新的 Ingress
                ingress_manifest = {
                    'apiVersion': 'networking.k8s.io/v1',
                    'kind': 'Ingress',
                    'metadata': {
                        'name': ingress_dir
                    },
                    'spec': {
                        'rules': [
                            {
                                # 'host': 'www.cquxxz.top',  # 主机名符合规范的格式
                                'http': {
                                    'paths': [
                                        {
                                            'path': f'/{ingress_dir}/{new_service_name}',
                                            'pathType': 'Prefix',
                                            'backend': {
                                                'service': {
                                                    'name': new_service_name,
                                                    'port': {
                                                        'number': 80
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        ]
                    }
                }
                resp = v1.create_namespaced_ingress(body=ingress_manifest, namespace=namespace)
                print("Ingress created. status='%s'" % resp)
            else:
                raise e

    def get_pod_token(self, deploy_name, namespace="current-semester"):
        # import re
        # from kubernetes import client, config
        def getPod(name, namespace="current-semester"):
            if namespace == 'all':
                # 获取所有命名空间的 Pod 列表
                pod_list = self.v1.list_pod_for_all_namespaces(watch=False)
            else:
                # 获取指定命名空间的 Pod 列表
                pod_list = self.v1.list_namespaced_pod(namespace)
            # 提取必要信息并组织成字典列表
            for pod in pod_list.items:
                if name in pod.metadata.name:
                    return pod.metadata.name
            return None

        pod_name = getPod(deploy_name, namespace)
        if not pod_name:
            print("未找到 Pod 名称")
            return None
        # 获取 Pod 日志
        try:
            # 调用 Kubernetes API 获取 Pod 的日志
            pod_log = self.v1.read_namespaced_pod_log(name=pod_name, namespace=namespace)
            
            # 使用正则表达式从日志中提取 token
            token_match = re.search(r'token=(\w+)', pod_log)
            if token_match:
                token = token_match.group(1)
                # print(f"获取到的 token 是：{token}")
                return {'token': token, 'pod_name': pod_name}
            else:
                # print("无法从日志中获取 token.")
                return None
        except client.exceptions.ApiException as e:
            print(f"获取 Pod 日志时出错: {e}")

    def get_service_info(self, deploy_name, namespace="current-semester"):
        print("KubernetesManager.get_service_info")
        namespace = 'current-semester'  # 如果想要获取所有命名空间的 Service，请将 namespace 设置为 None
        service_list = self.v1.list_namespaced_service(namespace=namespace)

        # 打印 Service 列表
        print("Service 列表:")
        for service in service_list.items:
            if deploy_name in service.metadata.name:
                created_time = service.metadata.creation_timestamp
                name = service.metadata.name
                type = service.spec.type
                # selector = service.spec.selector.app
                cluster_ip = service.spec.cluster_ip
                port = service.spec.ports[0].node_port
                return {
                    "created_time": created_time, 
                    "name": name, 
                    "type": type, 
                    # "selector": selector, 
                    "cluster_ip": cluster_ip, 
                    "port": port
                }
        return None
    def get_podName_by_deploy(self, deploy_name, namespace='current-semester'):
        print("KubernetesManager.get_podName_by_deploy")
        pods = self.v1.list_namespaced_pod(namespace=namespace).items

        # 打印指定命名空间中的所有容器
        print("Containers in namespace: ", namespace)
        for pod in pods:
            print("Pod:", pod.metadata.name)
            if pod.metadata.name.startswith(deploy_name):
                return pod.metadata.name
        return None
            # for container in pod.spec.containers:
            #     print("  Container:", container.name)
           
    def delete_deploy(self, deploy_name, namespace='current-semester'):
        try :
            # 只要删除deployment就行，顺便会删除pod
            self.api_instance.delete_namespaced_deployment(deploy_name, namespace)
            
            # 还需要删除service
            try:
                self.v1.delete_namespaced_service(deploy_name, namespace)
            except Exception as e:
                self.v1.delete_namespaced_service(deploy_name+'-service', namespace)
            return True
        except Exception as e:

            return False

    def get_pods_load(self, namespace='current-semester'):
        api_instance = client.CustomObjectsApi()

        # 定义 Metrics API 的组、版本和资源路径
        group = 'metrics.k8s.io'
        version = 'v1beta1'
        resource_path = 'pods'

        # 发起请求获取指定命名空间中的所有 Pod 的 Metrics
        pods_metrics = api_instance.list_namespaced_custom_object(group, version, namespace, resource_path)
        data = {}
        # 遍历每个 Pod 的 Metrics，并打印容器的资源使用情况
        def convert_cpu(cpu_usage):
            return "{:.4g}".format(int(cpu_usage[:-1]) / 1000000) if cpu_usage[:-1]!='' else '0'  # 将 nanocores 转换为 millicores，并保留四位有效数字

        def convert_memory(memory_usage):
            return "{:.4g}".format(int(memory_usage[:-2]) / 1024) if memory_usage[:-2]!='' else '0'  # 将 KiB 转换为 MiB，并保留四位有效数字
        data = {}
        for pod_metric in pods_metrics['items']:
            pod_name = pod_metric['metadata']['name']
            containers_metrics = pod_metric['containers']
            for container_metric in containers_metrics:
                container_name = container_metric['name']
                cpu_usage = container_metric['usage']['cpu']
                memory_usage = container_metric['usage']['memory']
                data[pod_name] = {
                    "container_name": container_name,
                    "cpu": convert_cpu(cpu_usage),
                    "memory": convert_memory(memory_usage)
                }
        return data
    

def create_1000_pods():
    # res = k8sManager.get_pod_token(deploy_name=new_container_name, namespace='current-semester')
    # token = str(res['token'])
    k8s_manager = KubernetesManager()
    class_id = 29
    task_type = 'homework'
    task_id = 9
    stu_id = 20204300
    namespace = 'current-semester'
    
    for id in range(stu_id+1, stu_id+1000):
        # 使用不同的命名空间和容器名称创建容器

        container_name = f'{task_type}-{task_id}-{id}'
        teaching_source_dir = f'/nfs/bigdata2024/{class_id}/{task_type}/{task_id}/teachingSource'
        student_work_dir = f'/nfs/bigdata2024/{class_id}/{task_type}/{task_id}/stuSubmit/{id}'
        k8s_manager.create_deployment_and_service(namespace, container_name, teaching_source_dir,student_work_dir, container_name)


def create_pod():
    k8s_manager = KubernetesManager()
    class_id = 29
    task_type = 'homework'
    task_id = 9
    stu_id = 20208888
    namespace = 'current-semester'
    container_name = f'{task_type}-{task_id}-{stu_id}'
    teaching_source_dir = f'/nfs/bigdata2024/{class_id}/{task_type}/{task_id}/teachingSource'
    student_work_dir = f'/nfs/bigdata2024/{class_id}/{task_type}/{task_id}/stuSubmit/{stu_id}'
    k8s_manager.create_deployment_and_service(namespace, container_name, teaching_source_dir,student_work_dir, container_name)
    
# 创建 KubernetesManager 实例
if __name__ == '__main__':

    # # 使用不同的命名空间和容器名称创建容器
    # k8s_manager.update_ingress_with_new_pod(namespace, 'exam-13', 'exam-13-20204249')
    
    
    create_pod()

    # create_1000_pods()


    # manager = KubernetesManager()
    # data = manager.get_pods_load()
    # for k, v in data.items():
    #     print(k, v)